There is no spoon
Legacy:Firing Projectile Weapons
How UT2003 Weapons Work: Projectile Weapons
Contents
Easy Way[edit]
In English[edit]
The player hits the Fire button. The engine then executes the alias attached to Fire. The alias fire is set to Button bFire, and the exec command Fire(). Check aliases for more information on how this works but basically bFire is a boolean variable that is automatically set by the engine to true when the fire button is being held down, and false when the fire button is released. The engine has a native event set such that when bFire is held down the Pawn.Weapons.WeaponFire.ModeDoFire() is called. As well PlayerController.Fire() is called. It's important to note that these are two distinctly separate chains of events.
The Second Chain[edit]
The second chain is shorter, and as such will be examined first. PlayerController.Fire() checks to see if the game is currently paused, and if it is unpauses the game and returns without further action. If the game is not paused, PlayerController.Fire() calls Pawn.Fire().
exec function Fire( optional float F ) { if ( Level.Pauser == PlayerReplicationInfo ) { SetPause(false); return; } Pawn.Fire(F); }
Pawn.Fire() checks to see if there's a valid weapon, and if so executes Weapon.Fire(). You'll note the check against None; this prevents access nones from appearing when the player does not have a valid weapon. Similar error checking code should be introduced in any code you write.
function Fire( optional float F ) { if( Weapon!=None ) Weapon.Fire(F); }
Weapon.Fire() would seem to be the function that actually fires the weapon, but this is not true. The base Weapon.Fire() is actually empty. As an abstract class this would be expected, except that most every class that derives from Weapon fails to override Fire() with their own function. It is, effectively, blank for every weapon included with Unreal Tournament 2003.
simulated function Fire(float F) { }
The First Chain[edit]
The actual processing of the firing of the weapon occurs in the first chain of events mentioned above. There is no visible link in the UnrealScript code provided by Epic or extracted from UnrealEd from Unreal Tournament 2003 between the Fire alias and ModeDoFire(). The link is handled by the engine, natively, through the boolean variable bFire and ModeDoFire().
ModeDoFire is called based upon the player's currently selected weapon, and whether or not we're in the Fire or AltFire chain of events. They proceed identically; the major difference is that FireModeClass(0).ModeDoFire() is called with Fire, and FireModeClass(1).ModeDoFire() is called with AltFire. (FireModeClass(x) is defined in the weapon class, and directs the engine to the appropriate class to be called when a weapon is fired. See Weapon for more information.)
The first thing ModeDoFire does is check if firing is currently allowed. A variety of circumstances may exist to prevent firing: a timer may have to expire between shots, the player may not have ammunition, the player may be dead. If any of these circumstances are met ModeDoFire simply exits and acts as if fire was not pressed. Then, again, we split off into two chains of possible events.
The First Chain: Server[edit]
Wormbo: There's a small error in the Projectile Fire Flowchart. The ProcessTouch function isn't called by the engine. Instead the engine calls the Touch function which calculates the exact hitlocation and calls ProcessTouch.
Dante: It seems as if UT is calling Weapon.ClientStartFire/Weapon.ServerStartFire which sets WeaponFire.bIsFiring = true (in Weapon.StartFire) which might be the trigger to call modeDoFire.
Ceej: Excellent flowchart, thank you. This is really the page to start with when attempting to understand weapons. The general weapon firing page still has the misleading PlayerController.Fire() call chain front and center. Maybe move the flowchart onto the general page and save this for projectile specifics?
Solid Snake: I've been dealing with the weapon code a lot now for the last 12 hours, and it seems that there is a little more complxities to this than detailed about. Other statements such as ServerStartFire(), ClientStartFire() and StartFire() all seem to play an important role into what makes the gun fire, of course you can always called DoFireMode to force fire the gun, but you miss out some other checks as well that may be important to make sure that the gun is fired properly over a network game. I'm not exactly to sure about this at the moment, but I will report back about this on my studies in this area. The one thing I can say is that Epic certainly doesn't make any easier to decipher what exactly is going on.